package advance.JVM.multithread;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * description: <br>
 * createTime: 2019/1/716:06 <br>
 *
 * @author zzh
 */
public class MultipleThreadTest {

    private static final int MIN_SIZE_PER_THREAD = 4000;
    private static int getThreadCount(int dataSize) {
        if(dataSize < MIN_SIZE_PER_THREAD * 10) {
            if(dataSize % MIN_SIZE_PER_THREAD == 0) {
                return dataSize / MIN_SIZE_PER_THREAD;
            } else {
                return dataSize / MIN_SIZE_PER_THREAD + 1;
            }
        }
        return 10;
    }
    public static void main(String[] args) throws InterruptedException {

        List<String> data = new ArrayList();
        int maxLoopNum = getThreadCount(data.size());
        CountDownLatch countDownLatch = new CountDownLatch(maxLoopNum);
        SqlSessionFactory sqlSessionFactory = null;
        for (int i = 0; i < maxLoopNum; i++) {
            int startIndex = i * MIN_SIZE_PER_THREAD;
            int endIndex;
            if(i != (maxLoopNum - 1)) {
                endIndex = i * (MIN_SIZE_PER_THREAD + 1);
            } else {
                endIndex = data.size() - startIndex;
            }
            new Thread(new Task<String, List<String>>(data, startIndex, endIndex, (s) -> {
                List<String> list = new ArrayList<>();
                list.add(s);
                return list;
            }, sqlSessionFactory.openSession(), String.class, Object.class, countDownLatch)).start();

        }
        countDownLatch.await();
        System.out.println("over");
    }
    static class Task<T, M> implements Runnable {
        private List<T> data;
        private int startIndex;
        private int endIndex;
        private Provider<T, M> provider;
        private SqlSession sqlSession;
        private Class<T> tClass;
        private Class mClass;
        private CountDownLatch countDownLatch;


        public Task(List<T> data, int startIndex, int endIndex, Provider<T, M> provider, SqlSession sqlSession, Class<T> tClass, Class mClass, CountDownLatch countDownLatch) {
            this.data = data;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.provider = provider;
            this.sqlSession = sqlSession;
            this.tClass = tClass;
            this.mClass = mClass;
            this.countDownLatch = countDownLatch;
        }


        @Override
        public void run() {
            //遍历list指定数据段，做处理
            Object mapper = sqlSession.getMapper(mClass);
            int count = 0;
            try {
                Method insert = mClass.getClass().getMethod("insert", new Class[]{tClass});
                for (int i = startIndex; i < endIndex; i++, count++) {
                    Object o = provider.provide(data.get(i));

                    insert.invoke(mapper, o);
                    if((count + 1) % MIN_SIZE_PER_THREAD == 0) {
                        sqlSession.flushStatements();
                    }
                }
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
            sqlSession.flushStatements();
            countDownLatch.countDown();
        }
    }
}

//传入一个类的实例，生成另一个类的实例返回
@FunctionalInterface
interface Provider<T, R>{
    R provide(T t);
}